#include "SpaceScene.hpp"

SpaceScene::~SpaceScene()
{
    delete entityManagement;
    for (auto it : components_list)
    {
        delete it;
    }
}

void SpaceScene::init()
{
    entityManagement = new EntityManagement();
    Data *data = Data::getInstance();
    ym::Json::Object map_object = data->getData("textmap")->getObject();
    ym::Json::Array ships_array = map_object.at("ships")->getArray();
    map_width = map_object.at("mapwidth")->getInt();
    map_height = map_object.at("mapheight")->getInt();

    Static::mapSize = Vector2(map_width,map_height);

    entityManagement->followRange = data->getData("config")->get("followrange")->getInt();
    for (auto it = ships_array.begin(); it != ships_array.end(); ++it)
    {
        ym::Json::Object ships_object = (*it)->getObject();
        ym::Json::Array pos_array = ships_object.at("position")->getArray();
        int count = ships_object.at("count")->getInt();
        Vector2 pos(Vector2(pos_array.at(0)->getDouble(), pos_array.at(1)->getDouble()));
        int owerId = ships_object.at("owner")->getInt();
        real facing = ships_object.at("facing")->getDouble();
        ym::Json *ships_jsondata = data->getData(ships_object.at("name")->getString().c_str());
        for (int i = 0; i < count; ++i)
        {
            Entity *entity = entityManagement->createShip(ships_jsondata, pos, owerId, facing);
            auto it2 = ships_object.find("slots");
            if (it2 != ships_object.end())
            {
                entityManagement->createParts(entity, (*it2).second);
            }
        }
    }
    ym::Json::Array golds_array = map_object.at("golds")->getArray();
    for (auto it = golds_array.begin(); it != golds_array.end(); ++it)
    {
        int count = (*it)->get("count")->getInt();
        real facing = (*it)->get("facing")->getDouble();
        real range = (*it)->get("range")->getDouble();
        ym::Json::Array array = (*it)->get("position")->getArray();
        Vector2 pos = Vector2(array.at(0)->getDouble(), array.at(1)->getDouble());
        real rad = facing * PI / 180;
        real d = 96 / range;
        rad = rad - (count / 2) * d;
        for (int i = 0; i < count; ++i)
        {
            ym::Json::Object obj = (*it)->getObject();
            Vector2 pos2 = pos + Vector2(range * so_cos(rad + i * d), range * so_sin(rad + i * d));
            auto it2 = obj.find("slots");
            Entity *entity = entityManagement->createGold(pos2);
            if (it2 != obj.end())
            {
                entityManagement->createParts(entity, (*it2).second);
            }
        }
    }

    camera.position = Vector2();
    camera.view_width = width;
    camera.view_height = height;

    btn_move = new Button("移动", {0, 0});
    btn_stop = new Button("停止", {0, 0});
    btn_hold = new Button("保持", {0, 0});
    btn_attack = new Button("攻击", {0, 0});
    btn_patrol = new Button("巡逻", {0, 0});

    btn_move->setHotkey('M');
    btn_stop->setHotkey('S');
    btn_hold->setHotkey('H');
    btn_attack->setHotkey('A');
    btn_patrol->setHotkey('P');

    btn_attack->setIcon("ui_action_attack");
    btn_attack->setIconHover("ui_action_attack_hover");
    btn_move->setIcon("ui_action_move");
    btn_move->setIconHover("ui_action_move_hover");
    btn_stop->setIcon("ui_action_stop");
    btn_stop->setIconHover("ui_action_stop_hover");
    btn_patrol->setIcon("ui_action_patrol");
    btn_patrol->setIconHover("ui_action_patrol_hover");
    btn_hold->setIcon("ui_action_hold");
    btn_hold->setIconHover("ui_action_hold_hover");

    components_list.push_back(btn_move);
    components_list.push_back(btn_stop);
    components_list.push_back(btn_hold);
    components_list.push_back(btn_attack);
    components_list.push_back(btn_patrol);
    updateSize();
    game_timer.recordTimePoint();
}

void SpaceScene::renderUI(SDL_Renderer *renderer)
{
    QuadTree *qtree = entityManagement->getQuadTree();
    if (Static::showQuadTree && qtree != nullptr)
    {
        auto qr = qtree->getRectangles();
        SDL_SetRenderDrawColor(renderer, 0xff, 0, 0xff, 0xff);
        for (auto it = qr->begin(); it != qr->end(); ++it)
        {
            Vector2 size = (*it)->getSize();
            Vector2 pos = (*it)->getPosition();
            SDL_Rect rc = {pos.x - camera.position.x, pos.y - camera.position.y, size.x, size.y};
            SDL_RenderDrawRect(renderer, &rc);
        }
        delete qr;
    }
    SDL_Rect bottom_rc = {ui_bottom_x, ui_bottom_y, ui_bottom_width, ui_bottom_height};
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0xff, 0x90);
    SDL_RenderFillRect(renderer, &bottom_rc);
    SDL_Rect group_rc = {ui_group_x, ui_group_y, ui_group_width, ui_group_height};
    SDL_SetRenderDrawColor(renderer, 0, 0x90, 0xff, 0x50);
    SDL_RenderFillRect(renderer, &group_rc);
    const std::vector<Entity *> *selected_list = entityManagement->getSelected();
    for (auto it : components_list)
    {
        it->render(renderer);
    }
    if (!selected_list->empty())
    {
        int count = 0;
        int x = ui_group_icon_x;
        int y = ui_group_icon_y;
        for (auto it = selected_list->begin(); it != selected_list->end(); ++it)
        {
            Ship *ship = (Ship *)*it;
            if (ship->isExited())
            {
                continue;
            }
            if (count >= 2 * 8)
            {
                continue;
            }
            SDL_Rect rc = {x, y, ui_group_icon_width, ui_group_icon_height};
            Image *icon_image = ship->getImage();
            SDL_Texture *icon_tex = icon_image->getTexture(renderer);
            SDL_SetTextureColorMod(icon_tex, 0xff, 0xff, 0xff);
            real angle = -icon_image->getAngle();
            SDL_RenderCopyEx(renderer, icon_tex, nullptr, &rc, angle, nullptr, SDL_FLIP_NONE);
            int hpbar_width = ui_group_icon_width / 2;
            int hpbar_height = hpbar_width / 10;
            SDL_Rect hpbar_rc = {rc.x + (ui_group_icon_width - hpbar_width) / 2, rc.y + ui_group_icon_width - hpbar_height * 2, hpbar_width, hpbar_height};
            SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0x90);
            SDL_RenderFillRect(renderer, &hpbar_rc);
            hpbar_rc.w = ship->getHp() / ship->getMaxHp() * hpbar_width;
            SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0x90);
            SDL_RenderFillRect(renderer, &hpbar_rc);

            x += ui_group_icon_width;
            if (count % 8 == 7)
            {
                x = ui_group_icon_x;
                y += ui_group_icon_height;
            }
            count++;
        }

        Ship *ship = (Ship *)selected_list->at(0);
        if (ship != nullptr)
        {
            int gold = 0;
            for (int i = 0; i < 4; ++i)
            {
                if (ship->slots[i].part != nullptr && ship->slots[i].part->gold > 0)
                {
                    gold += ship->slots[i].part->gold;
                }
            }
            char str[BUFSIZ] = {};
            sprintf_s(str, sizeof(str), "%s hp: %4.0f / %4.0f velocity: %4.0f state:%d carry:%d/%d gold:%d", ship->name, ship->getHp(), ship->getMaxHp(), ship->getVelocity(), ship->orderType, ship->getCarry(), ship->getCapacity(), gold);
            SDL_Color color = {0xff, 0xff, 0xff};
            SDL_Surface *text_sur = TTF_RenderUTF8_Blended(Static::default_font, str, color);
            SDL_Texture *text_tex = SDL_CreateTextureFromSurface(renderer, text_sur);
            int w, h;
            TTF_SizeUTF8(Static::default_font, str, &w, &h);
            SDL_Rect rc = {(width - w) / 2, height - h, w, h};
            SDL_RenderCopy(renderer, text_tex, nullptr, &rc);
            SDL_DestroyTexture(text_tex);
            SDL_FreeSurface(text_sur);
        }
    }

    SDL_Color color = {0xff, 0xff, 0xff, 0xff};
    char buff[32];
    SDL_snprintf(buff, sizeof(buff), "gold:%d", Static::golds[Static::playerID]);
    SDL_Surface *gold_sur = TTF_RenderUTF8_Blended(Static::default_font, buff, color);
    SDL_Texture *gold_tex = SDL_CreateTextureFromSurface(renderer, gold_sur);
    TTF_SizeUTF8(Static::default_font, buff, &ui_gold_icon_width, nullptr);
    SDL_Rect gold_rc = {ui_gold_icon_x, ui_gold_icon_y, ui_gold_icon_width, ui_gold_icon_height};
    SDL_RenderCopy(renderer, gold_tex, nullptr, &gold_rc);
    SDL_DestroyTexture(gold_tex);
    SDL_FreeSurface(gold_sur);

    SDL_Rect map_rc = {ui_map_x - 8, ui_map_y - 8, ui_map_height + 2 * 8, ui_map_width + 2 * 8};
    SDL_SetRenderDrawColor(renderer, 0, 0, 0xff, 0x90);
    SDL_RenderFillRect(renderer, &map_rc);
    SDL_Rect map_inner_rc = {ui_map_x, ui_map_y, ui_map_height, ui_map_width};
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xff);
    SDL_RenderFillRect(renderer, &map_inner_rc);
    real w = map_inner_rc.w * camera.view_width / (real)map_width;
    real h = map_inner_rc.h * camera.view_height / (real)map_height;
    int x = camera.position.x * map_inner_rc.w / (real)map_width + map_inner_rc.x;
    int y = camera.position.y * map_inner_rc.h / (real)map_height + map_inner_rc.y;
    SDL_Rect map_camera_rc = {x, y, w, h};
    auto list = entityManagement->getEntities();
    SDL_Rect map_entity_rc;
    int highlight = 0xff;
    int normal = 0xb0;
    int min = 2;
    int max = 32;
    for (auto it = list->begin(); it != list->end(); ++it)
    {
        Ship *ship = (Ship *)*it;
        if (ship->isSelected)
        {
            continue;
        }
        map_entity_rc.x = (*it)->getPosition().x * map_inner_rc.w / (real)map_width + map_inner_rc.x;
        map_entity_rc.y = (*it)->getPosition().y * map_inner_rc.h / (real)map_height + map_inner_rc.y;
        map_entity_rc.w = ship->selectedSize * map_inner_rc.w / (real)map_width;
        map_entity_rc.h = ship->selectedSize * map_inner_rc.h / (real)map_height;
        map_entity_rc.w = so_between(map_entity_rc.w, min, max);
        map_entity_rc.h = so_between(map_entity_rc.h, min, max);

        int c = normal;
        if (ship->getOwnerID() == Static::playerID)
        {
            SDL_SetRenderDrawColor(renderer, c, c, c, 0xff);
        }
        else if (ship->getOwnerID() == 13)
        {
            SDL_SetRenderDrawColor(renderer, c, c, 0, 0xff);
        }
        else
        {
            SDL_SetRenderDrawColor(renderer, c, 0, 0, 0xff);
        }
        SDL_RenderFillRect(renderer, &map_entity_rc);
    }

    for (auto it = selected_list->begin(); it != selected_list->end(); ++it)
    {
        Ship *ship = (Ship *)*it;
        map_entity_rc.x = (*it)->getPosition().x * map_inner_rc.w / (real)map_width + map_inner_rc.x;
        map_entity_rc.y = (*it)->getPosition().y * map_inner_rc.h / (real)map_height + map_inner_rc.y;
        map_entity_rc.w = ship->selectedSize * map_inner_rc.w / (real)map_width;
        map_entity_rc.h = ship->selectedSize * map_inner_rc.h / (real)map_height;
        map_entity_rc.w = so_between(map_entity_rc.w, min, max);
        map_entity_rc.h = so_between(map_entity_rc.h, min, max);

        int c = highlight;
        if (ship->getOwnerID() == Static::playerID)
        {
            SDL_SetRenderDrawColor(renderer, c, c, c, 0xff);
        }
        else if (ship->getOwnerID() == 13)
        {
            SDL_SetRenderDrawColor(renderer, c, c, 0, 0xff);
        }
        else
        {
            SDL_SetRenderDrawColor(renderer, c, 0, 0, 0xff);
        }
        SDL_RenderFillRect(renderer, &map_entity_rc);
    }
    SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);
    SDL_RenderDrawRect(renderer, &map_camera_rc);

    msg.render(renderer);
}

void SpaceScene::render(SDL_Renderer *renderer)
{
    Timer dt;
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
    SDL_Texture *bg_tex = Resource::getInstance()->getImage("background_black")->getTexture(renderer);
    SDL_RenderCopy(renderer, bg_tex, nullptr, nullptr);
    renderEntities(renderer);
    Vector2 start_pos = -camera.position;
    const std::vector<Entity *> *hovers = entityManagement->getHover();
    if (Static::showMesh)
    {
        const Mesh2D *mesh = entityManagement->getMesh();
        for (int i = 0; i < mesh->meshHeight; ++i)
        {
            for (int j = 0; j < mesh->meshWidth; ++j)
            {
                SDL_Rect mesh_rect = {j * mesh->cellSize + start_pos.x, i * mesh->cellSize + start_pos.y, mesh->cellSize, mesh->cellSize};
                SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0x80);
                SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
                if (mesh->data[i * mesh->meshWidth + j])
                {
                    SDL_RenderFillRect(renderer, &mesh_rect);
                }
                else
                {
                    SDL_RenderDrawRect(renderer, &mesh_rect);
                }
            }
        }
    }
    for (auto it = hovers->begin(); it != hovers->end(); ++it)
    {
        Ship *ship = (Ship *)*it;
        int hpbar_width = ship->selectedSize / 2;
        int hpbar_height = hpbar_width / 10;
        SDL_Rect hpbar_rc = {ship->getPosition().x - hpbar_width / 2 + start_pos.x, ship->getPosition().y - ship->selectedSize / 2 + start_pos.y, hpbar_width, hpbar_height};
        SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0);
        SDL_RenderFillRect(renderer, &hpbar_rc);
        hpbar_rc.w = ship->getHp() / ship->getMaxHp() * hpbar_width;
        SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0);
        SDL_RenderFillRect(renderer, &hpbar_rc);
    }

    if (press_left)
    {
        SDL_Rect rc = {drag_x - camera.position.x, drag_y - camera.position.y, cursor_x + camera.position.x - drag_x, cursor_y + camera.position.y - drag_y};
        SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
        SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0x60);
        SDL_RenderFillRect(renderer, &rc);
    }
    renderEffects(renderer);
    auto collisions = entityManagement->getCollisions();
    if (Static::showCollision)
    {
        for (auto it = collisions->begin(); it != collisions->end(); ++it)
        {
            Collision *col = *it;
            SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0, 0x90);
            SDL_RenderDrawLine(renderer, col->a->getPosition().x + start_pos.x, col->a->getPosition().y + start_pos.y, col->b->getPosition().x + start_pos.x, col->b->getPosition().y + start_pos.y);
        }
    }
    renderBullets(renderer);
    renderUI(renderer);
    const std::list<CollisionEntity *> *list = entityManagement->getCollisionEntities();
    if (Static::showAABB)
    {
        for (auto it = list->begin(); it != list->end(); ++it)
        {
            CollisionEntity *col = *it;
            const AABB *aabb = col->getAABB();
            SDL_Rect aabb_rc = {aabb->ul.x + start_pos.x, aabb->ul.y + start_pos.y, aabb->dr.x - aabb->ul.x, aabb->dr.y - aabb->ul.y};
            SDL_Color color = {0xff, 0xff, 0xff};
            char buff[0xff];
            sprintf_s(buff, 0xff, "%d", col->layer);
            SDL_SetRenderDrawBlendMode(renderer, SDL_BlendMode::SDL_BLENDMODE_BLEND);
            SDL_SetRenderDrawColor(renderer, 0, 0xff, 0xff, 0x60);
            SDL_RenderFillRect(renderer, &aabb_rc);
            SDL_Surface *sur = TTF_RenderUTF8_Blended(Static::default_font, buff, color);
            SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, sur);
            SDL_SetTextureScaleMode(tex, SDL_ScaleMode::SDL_ScaleModeLinear);
            SDL_RenderCopy(renderer, tex, nullptr, &aabb_rc);
            SDL_DestroyTexture(tex);
            SDL_FreeSurface(sur);
        }
    }
    auto edges = entityManagement->getNavmesh()->getEdge();
    if (Static::showNavmesh)
    {
        for (auto it = edges->begin(); it != edges->end(); ++it)
        {
            const Vector2 ps[] = {(*it)->p1 + start_pos, (*it)->p2 + start_pos};
            if ((*it)->isRestrain)
            {
                SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0xff);
            }
            else
            {
                SDL_SetRenderDrawColor(renderer, 0, 0xff, 0xff, 0xff);
            }
            SDL_RenderDrawLine(renderer, ps[0].x, ps[0].y, ps[1].x, ps[1].y);
        }
    }
    // auto elist = entityManagement->getNavmesh()->ts;
    // for (auto it = elist.begin(); it != elist.end(); ++it)
    // {
    //     NavPathEdge *e = *it;
    //     SDL_SetRenderDrawColor(renderer, 0xff, 0, 0xff, 0xff);
    //     SDL_RenderDrawLine(renderer, e->p1.x + start_pos.x, e->p1.y + start_pos.y, e->p2.x + start_pos.x, e->p2.y + start_pos.y);
    // }
    // auto lefts = entityManagement->getNavmesh()->lefts;
    // auto rights = entityManagement->getNavmesh()->rights;

    // for (int i = 0; i < lefts.size(); ++i)
    // {
    //     SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0x90);
    //     SDL_Rect rc = {lefts[i].x + start_pos.x - 10, lefts[i].y + start_pos.y - 10, 20, 20};
    //     SDL_RenderFillRect(renderer, &rc);
    //     char buff[0xff];
    //     sprintf(buff, "%d", i);
    //     SDL_Surface *sur = TTF_RenderUTF8_Blended(Static::default_font, buff, {0xff, 0, 0, 0xff});

    //     SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, sur);
    //     SDL_RenderCopy(renderer, tex, nullptr, &rc);
    //     SDL_DestroyTexture(tex);
    //     SDL_FreeSurface(sur);
    // }

    // for (int i = 0; i < rights.size(); ++i)
    // {
    //     SDL_SetRenderDrawColor(renderer, 0, 0, 0xff, 0x90);
    //     SDL_Rect rc = {rights[i].x + start_pos.x - 10, rights[i].y + start_pos.y - 10, 20, 20};
    //     SDL_RenderFillRect(renderer, &rc);

    //     char buff[0xff];
    //     sprintf(buff, "%d", i);
    //     SDL_Surface *sur = TTF_RenderUTF8_Blended(Static::default_font, buff, {0xff, 0, 0, 0xff});

    //     SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, sur);
    //     SDL_RenderCopy(renderer, tex, nullptr, &rc);
    //     SDL_DestroyTexture(tex);
    //     SDL_FreeSurface(sur);
    // }

    // auto lines = entityManagement->getNavmesh()->lines;

    // for (int i = 0; i < lines.size(); ++i)
    // {
    //     Edge e = lines[i];
    //     e.p1 += start_pos;
    //     e.p2 += start_pos;
    //     SDL_SetRenderDrawColor(renderer, 0xff, 0, 0xff, 0xff);
    //     if (i == 0)
    //     {
    //         SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);
    //     }
    //     SDL_RenderDrawLine(renderer, e.p1.x, e.p1.y, e.p2.x, e.p2.y);
    // }
    // for (int i = 0; i < entityManagement->getNavmesh()->ts.size(); ++i)
    // {
    //     Vector2 ps[2] = {entityManagement->getNavmesh()->ts[i]->p1 + start_pos, entityManagement->getNavmesh()->ts[i]->p2 + start_pos};
    //     // SDL_Color cols[2] = {{0xff, 0, 0, 0xff}, {0, 0xff, 0, 0xff}};
    //     int x, y;
    //     SDL_SetRenderDrawColor(renderer,0,0xff,0,0xff);
    //     if (entityManagement->getNavmesh()->ts[i]->cross)
    //     {
    //         x = ps[0].x - 10;
    //         y = ps[0].y - 10;
    //     }
    //     else
    //     {
    //         x = ps[1].x - 10;
    //         y = ps[1].y - 10;
    //     }
    //     SDL_Rect rc = {x,
    //                    y,
    //                    20,
    //                    20};

    //     SDL_RenderFillRect(renderer, &rc);
    // }
    auto trilist = entityManagement->getNavmesh()->getTriangles();
    char buff[0xff];
    SDL_snprintf(buff, 0xff, "nav tris:%d edges %d", trilist->size(), edges->size());
    viewable_list.push_back(buff);
    SDL_snprintf(buff, 0xff, "render cost: %ldms", dt.getElapsedMilliseconds());
    viewable_list.push_back(buff);
    SDL_snprintf(buff, 0xff, "collisionEntities count: %d", list->size());
    viewable_list.push_back(buff);
}

void SpaceScene::renderEntities(SDL_Renderer *renderer)
{
    const std::vector<Entity *> *entities_list = entityManagement->getEntities();
    if (entities_list == nullptr)
    {
        return;
    }
    char buff[0xff];
    SDL_snprintf(buff, 0xff, "entities count: %d", entities_list->size());
    viewable_list.push_back(buff);
    SDL_Texture *selected_tex = Resource::getInstance()->getImage("selected_1")->getTexture(renderer);
    SDL_SetTextureScaleMode(selected_tex, SDL_ScaleMode::SDL_ScaleModeBest);
    Vector2 start_pos = -camera.position;
    for (auto it = entities_list->begin(); it != entities_list->end(); ++it)
    {
        Entity *entity = *it;
        Ship *ship = (Ship *)entity;
        if (entity == nullptr || entity->isExited())
        {
            continue;
        }
        Image *single_image = entity->getImage();
        if (entity->isSelected)
        {
            SDL_Rect rc_selected = {entity->getPosition().x - entity->selectedSize / 2 + start_pos.x, entity->getPosition().y - entity->selectedSize / 2 + start_pos.y, entity->selectedSize, entity->selectedSize};
            if (((Ship *)entity)->getOwnerID() == Static::playerID)
            {
                SDL_SetTextureColorMod(selected_tex, 0, 0xff, 0);
            }
            else if (((Ship *)entity)->getOwnerID() == 13)
            {
                SDL_SetTextureColorMod(selected_tex, 0xff, 0xff, 0);
            }
            else
            {
                SDL_SetTextureColorMod(selected_tex, 0xff, 0, 0);
            }
            SDL_SetTextureBlendMode(selected_tex, SDL_BLENDMODE_BLEND);
            SDL_RenderCopy(renderer, selected_tex, nullptr, &rc_selected);
        }
        if (single_image)
        {
            SDL_Texture *image_tex = single_image->getTexture(renderer);
            SDL_Rect rc = {(int)entity->getPosition().x - entity->getRenderSize().x / 2 + start_pos.x, ((int)entity->getPosition().y - entity->getRenderSize().y / 2) + start_pos.y, (int)entity->getRenderSize().x, (int)entity->getRenderSize().y};
            real angle = so_stdangle(entity->getFacing()) + single_image->getAngle();
            if (((Ship *)entity)->getOwnerID() == Static::playerID)
            {
                SDL_SetTextureColorMod(image_tex, 0, 0, 0xff);
            }
            else if (((Ship *)entity)->getOwnerID() == 13)
            {
                SDL_SetTextureColorMod(image_tex, 0xff, 0xff, 0xff);
            }
            else
            {
                SDL_SetTextureColorMod(image_tex, 0xff, 0, 0);
            }
            SDL_SetTextureScaleMode(image_tex, SDL_ScaleMode::SDL_ScaleModeBest);
            SDL_RenderCopyEx(renderer, image_tex, nullptr, &rc, so_stdangle(angle), nullptr, SDL_FLIP_NONE);
        }
        Slot *slots = entity->getSlots();
        for (int i = 0; i < 4; i++)
        {
            if (slots[i].part != nullptr)
            {
                Image *img = (Image *)slots[i].part->getImage();
                SDL_Texture *img_tex = img->getTexture(renderer);
                if (img_tex == nullptr)
                {
                    break;
                }
                Vector2 pos = entity->getSlotPosition(i);
                Vector2 pos2 = entity->getSlotPosition(i) - slots[i].part->getRenderSize() / 2;
                SDL_Rect part_rc = {pos2.x + start_pos.x, pos2.y + start_pos.y, slots[i].part->getRenderSize().x, slots[i].part->getRenderSize().y};
                SDL_RenderCopyEx(renderer, img_tex, nullptr, &part_rc, slots[i].part->getFacing() - img->getAngle(), nullptr, (SDL_RendererFlip)slots[i].flip);
                if (Static::showFacing)
                {
                    SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0xff);
                    Vector2 pos = entity->getSlotPosition(i);
                    real rad = slots[i].part->getFacing() * PI / 180;
                    real length = 50;
                    SDL_RenderDrawLine(renderer, pos.x, pos.y, pos.x + length * so_cos(rad), pos.y + length * so_sin(rad));
                }
                if (slots[i].part->animation != nullptr)
                {
                    IAnimation *ani = (IAnimation *)slots[i].part->animation;
                    if (ani != nullptr && ani->isVisible())
                    {
                        Image *image = ani->getImage();
                        SDL_Texture *image_tex = image->getTexture(renderer);

                        real length = ani->getOffset().length();

                        real rad = slots[i].part->getFacing() * PI / 180;
                        real rad2 = so_atan2(ani->getOffset().y, ani->getOffset().x);
                        real rad3 = (rad - rad2 + PI / 2);
                        pos.x += (length * so_cos(rad3)) + start_pos.x;
                        pos.y += (length * so_sin(rad3)) + start_pos.y;

                        SDL_SetTextureColorMod(image_tex, 0xff, 0x90, 0);
                        if (ani->getAnchor() == Anchor::Top)
                        {
                            SDL_Rect rc_animation = {pos.x - ani->getRenderSize().x / 2, pos.y, ani->getRenderSize().x, ani->getRenderSize().y};
                            SDL_Point p = {rc_animation.w / 2, 0};
                            SDL_RenderCopyEx(renderer, image_tex, nullptr, &rc_animation, slots[i].part->getFacing() - image->getAngle(), &p, SDL_FLIP_NONE);
                        }
                        else if (ani->getAnchor() == Anchor::Bottom)
                        {
                            SDL_Rect rc_animation = {pos.x - ani->getRenderSize().x / 2, pos.y - ani->getRenderSize().y, ani->getRenderSize().x, ani->getRenderSize().y};
                            SDL_Point p = {rc_animation.w / 2, rc_animation.h};
                            SDL_RenderCopyEx(renderer, image_tex, nullptr, &rc_animation, slots[i].part->getFacing() - image->getAngle(), &p, SDL_FLIP_NONE);
                        }
                        else if (ani->getAnchor() == Anchor::Left)
                        {
                            SDL_Rect rc_animation = {pos.x, pos.y - ani->getRenderSize().y / 2, ani->getRenderSize().x / 2, ani->getRenderSize().y};
                            SDL_Point p = {0, rc_animation.h / 2};
                            SDL_RenderCopyEx(renderer, image_tex, nullptr, &rc_animation, slots[i].part->getFacing() - image->getAngle(), &p, SDL_FLIP_NONE);
                        }
                        else if (ani->getAnchor() == Anchor::Right)
                        {
                            SDL_Rect rc_animation = {pos.x + ani->getRenderSize().x, pos.y - ani->getRenderSize().y / 2, ani->getRenderSize().x / 2, ani->getRenderSize().y};
                            SDL_Point p = {rc_animation.w, rc_animation.h / 2};
                            SDL_RenderCopyEx(renderer, image_tex, nullptr, &rc_animation, slots[i].part->getFacing() - image->getAngle(), &p, SDL_FLIP_NONE);
                        }
                    }
                }
            }
        }
        if (entity->hover)
        {

            SDL_Rect rc_hover = {entity->getPosition().x - entity->selectedSize / 2 + start_pos.x, entity->getPosition().y - entity->selectedSize / 2 + start_pos.y, entity->selectedSize, entity->selectedSize};
            SDL_Texture *hover_tex = Resource::getInstance()->getImage("selected_2")->getTexture(renderer);
            if (((Ship *)entity)->getOwnerID() == Static::playerID)
            {
                SDL_SetTextureColorMod(hover_tex, 0, 0xff, 0);
            }
            else if (((Ship *)entity)->getOwnerID() == 13)
            {
                SDL_SetTextureColorMod(hover_tex, 0xff, 0xff, 0);
            }
            else
            {
                SDL_SetTextureColorMod(hover_tex, 0xff, 0, 0);
            }
            SDL_SetTextureBlendMode(hover_tex, SDL_BLENDMODE_BLEND);
            SDL_SetTextureScaleMode(hover_tex, SDL_ScaleMode::SDL_ScaleModeLinear);
            SDL_RenderCopy(renderer, hover_tex, nullptr, &rc_hover);
        }
    }

    for (auto it = entities_list->begin(); it != entities_list->end(); ++it)
    {
        Entity *entity = (Entity *)*it;
        UnitOrder *order = entityManagement->getTopOrder(entity);
        if (Static::showTopOrder && order != nullptr)
        {
            Vector2 targetPos;
            if (order->type == UnitOrderType::ATTACK)
            {
                targetPos = order->data.targetOrder.target->getPosition();
                SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0x80);
            }
            else if (order->type == UnitOrderType::FOLLOW)
            {
                targetPos = order->data.targetOrder.target->getPosition();
                SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0x80);
            }
            else if (order->type == UnitOrderType::HARVEST)
            {
                if (order->data.harvestOrder.withdraw != nullptr)
                {
                    SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0x80);
                    targetPos = order->data.harvestOrder.withdraw->getPosition();
                    targetPos += start_pos;
                    SDL_RenderDrawLine(renderer, entity->getPosition().x + start_pos.x, entity->getPosition().y + start_pos.y, targetPos.x, targetPos.y);
                }
                SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0, 0x80);
                if (order->data.harvestOrder.harvest != nullptr)
                {
                    targetPos = order->data.harvestOrder.harvest->getPosition();
                }
            }
            else
            {
                SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0x80);
                targetPos = order->data.pointOrder.pos;
                if (order->data.pointOrder.path.size() > 0)
                {
                    SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0x80);
                    auto list = order->data.pointOrder.path;
                    Vector2 last = list.top() + start_pos;
                    while(!list.empty()){
                        Vector2 next = list.top() + start_pos;
                        SDL_RenderDrawLine(renderer, last.x, last.y, next.x, next.y);
                        last = next;
                        list.pop();
                    }
                    continue;
                }
            }
            targetPos += start_pos;
            SDL_RenderDrawLine(renderer, entity->getPosition().x + start_pos.x, entity->getPosition().y + start_pos.y, targetPos.x, targetPos.y);
        }
    }
}

void SpaceScene::renderEffects(SDL_Renderer *renderer)
{
    auto list = entityManagement->getEffects();
    char buff[0xff];
    SDL_snprintf(buff, 0xff, "effects count: %d", list->size());
    viewable_list.push_back(buff);
    for (auto it = list->begin(); it != list->end(); ++it)
    {
        Effect *effect = *it;
        IAnimation *ani = effect->getAnimation();
        Image *image = ani->getImage();
        SDL_Texture *ani_tex = image->getTexture(renderer);
        real angle = -effect->getFacing() + 360;
        real rad = -(so_rad(angle * PI / 180) - so_rad(so_atan2(-ani->getOffset().y, ani->getOffset().x))) + 2 * PI;
        real d = ani->getOffset().length();
        int offsetX = -so_sin(rad) * d;
        int offsetY = so_cos(rad) * d;
        SDL_Rect rc = {effect->getPosition().x - ani->getRenderSize().x / 2 + offsetX - camera.position.x, effect->getPosition().y - ani->getRenderSize().y / 2 + offsetY - camera.position.y, ani->getRenderSize().x, ani->getRenderSize().y};
        SDL_SetTextureColorMod(ani_tex, effect->getColor().r, effect->getColor().g, effect->getColor().b);
        SDL_SetTextureAlphaMod(ani_tex, effect->getColor().a);
        SDL_RenderCopyEx(renderer, ani_tex, nullptr, &rc, so_stdangle(angle + image->getAngle()), nullptr, SDL_FLIP_NONE);
    }
}

void SpaceScene::renderBullets(SDL_Renderer *renderer)
{
    Vector2 start_pos = -camera.position;
    auto list = entityManagement->getBullets();
    for (auto it = list->begin(); it != list->end(); ++it)
    {
        Bullet *bullet = *it;
        Image *single_image = bullet->getImage();
        if (single_image)
        {
            SDL_Texture *image_tex = single_image->getTexture(renderer);
            SDL_Rect rc = {(int)bullet->getPosition().x - bullet->getRenderSize().x / 2 + start_pos.x, ((int)bullet->getPosition().y - bullet->getRenderSize().y / 2) + start_pos.y, (int)bullet->getRenderSize().x, (int)bullet->getRenderSize().y};
            real angle = so_stdangle(bullet->getFacing()) + single_image->getAngle();
            SDL_SetTextureScaleMode(image_tex, SDL_ScaleMode::SDL_ScaleModeBest);
            SDL_RenderCopyEx(renderer, image_tex, nullptr, &rc, so_stdangle(angle), nullptr, SDL_FLIP_NONE);
        }
    }
    char buff[0xff];
    SDL_snprintf(buff, 0xff, "bullets count: %d", list->size());
    viewable_list.push_back(buff);
}

void SpaceScene::updateSize()
{
    int padding = height / 100;

    ui_map_height = height / 4 - 2 * padding;
    ui_map_width = ui_map_height;
    ui_map_x = padding * 2;
    ui_map_y = height - height / 4 + padding;

    ui_bottom_width = width / 1.2;
    ui_bottom_height = height / 4;
    ui_bottom_x = ui_map_x + padding * 2 + ui_map_width;
    ui_bottom_y = height - ui_bottom_height;

    ui_group_width = ui_bottom_width * 3 / 4;
    ui_group_height = ui_bottom_height - padding * 2;
    ui_group_x = ui_bottom_x + padding;
    ui_group_y = ui_bottom_y + padding;

    ui_group_icon_x = ui_group_x + padding;
    ui_group_icon_y = ui_group_y + padding;
    ui_group_icon_height = (ui_group_height - 2 * padding) / 4;
    ui_group_icon_width = ui_group_icon_height;

    int x = ui_group_x + ui_group_width + padding * 2;
    int w = 60;

    msg.msg_rect.w = 400;
    msg.msg_rect.x = width - 400;
    msg.msg_rect.y = 0;

    for (auto it = components_list.begin(); it != components_list.end(); ++it)
    {
        (*it)->setPosition(x, height * 3 / 4 + padding);
        (*it)->setSize(w, 60);
        (*it)->setVisible(false);
        (*it)->setValid(false);
        x += w;
    }

    ui_gold_icon_x = width - 200;
    ui_gold_icon_y = 0;
    ui_gold_icon_height = 32;
    ui_gold_icon_width = 32;
}

int SpaceScene::update(real delta)
{
    viewable_list.clear();
    Timer dt;
    entityManagement->update(delta);
    char buff[0xff];
    SDL_snprintf(buff, 0xff, "update cost: %ldms", dt.getElapsedMilliseconds());
    // viewable_list.push_back(buff);
    // SDL_snprintf(buff, 0xff, "cursor: (%d,%d)", cursor_x, cursor_y);
    viewable_list.push_back(buff);
    Vector2 cv((cursor_x >= width - 1) - (cursor_x <= 0), (cursor_y >= height - 1) - (cursor_y <= 0));
    if (cv != Vector2())
    {
        camera.position += (cv.normalized() * 1000 * delta);
        camera.position.x = so_max(0, camera.position.x);
        camera.position.y = so_max(0, camera.position.y);

        camera.position.x = so_min(map_width - width, camera.position.x);
        camera.position.y = so_min(map_height - height, camera.position.y);
    }
    if (press_left && drag_x >= ui_map_x && drag_y >= ui_map_y && drag_x <= ui_map_x + ui_map_width && drag_y <= ui_map_y + ui_map_height)
    {
        camera.position.x = (cursor_x - ui_map_x) * (real)map_width / (ui_map_width)-camera.view_width / 2;
        camera.position.y = (cursor_y - ui_map_y) * (real)map_height / ui_map_height - camera.view_height / 2;
        camera.position.x = so_between(camera.position.x, 0, map_width - camera.view_width);
        camera.position.y = so_between(camera.position.y, 0, map_height - camera.view_height);
    }
    for (auto it : components_list)
    {
        it->update(delta);
    }
    SDL_snprintf(buff, 0xff, "game time: %ds", game_timer.getElapsedSeconds());
    viewable_list.push_back(buff);
    msg.update(delta);
    return 0;
}

int SpaceScene::handleEvent(SDL_Event &evt)
{
    bool mark = false;
    for (auto it = components_list.begin(); it != components_list.end(); ++it)
    {
        if (evt.type == SDL_WINDOWEVENT && evt.window.event == SDL_WINDOWEVENT_RESIZED)
        {
            width = evt.window.data1;
            height = evt.window.data2;
            updateSize();
        }
        else if ((*it)->handleEvent(evt))
        {
            mark = true;
            auto list = *entityManagement->getSelected();
            if (evt.type != SDL_MOUSEBUTTONUP && evt.type != SDL_KEYUP)
            {
                continue;
            }
            if (list.empty() || ((Ship *)list.at(0))->getOwnerID() != Static::playerID)
            {
                continue;
            }
            if (((Button *)*it) == btn_stop)
            {
                for (auto entity : list)
                {
                    entityManagement->unitStop(entity);
                }
            }
        }
    }
    if (mark)
    {
        return 0;
    }

    const Uint8 *keys_state = SDL_GetKeyboardState(NULL);
    bool sft = keys_state[SDL_SCANCODE_LSHIFT] || keys_state[SDL_SCANCODE_RSHIFT];
    bool ctl = keys_state[SDL_SCANCODE_LCTRL] || keys_state[SDL_SCANCODE_RCTRL];
    bool alt = keys_state[SDL_SCANCODE_ALTERASE] || keys_state[SDL_SCANCODE_ALTERASE];
    int mask = (sft << 2) + (ctl << 1) + (alt << 0);
    if (evt.type == SDL_MOUSEBUTTONDOWN)
    {
        if (evt.button.button == SDL_BUTTON_LEFT)
        {
            drag_x = evt.motion.x + camera.position.x;
            drag_y = evt.motion.y + camera.position.y;
            press_left = true;
        }
        else if (evt.button.button == SDL_BUTTON_RIGHT)
        {
            entityManagement->rightClick(evt.button.x + camera.position.x, evt.button.y + camera.position.y, mask);
            msg.showMessage("右键点击", 0);
        }
    }
    else if (evt.type == SDL_MOUSEMOTION)
    {
        cursor_x = evt.motion.x;
        cursor_y = evt.motion.y;
        entityManagement->mouseMotion(evt.motion.x + camera.position.x, evt.motion.y + camera.position.y, mask);
    }
    else if (evt.type == SDL_MOUSEBUTTONUP)
    {
        if (evt.button.button == SDL_BUTTON_LEFT)
        {
            press_left = false;
            int w = so_abs(drag_x - evt.button.x - camera.position.x);
            int h = so_abs(drag_y - evt.button.y - camera.position.y);
            if (w > 5 || h > 5)
            {
                int x = so_min(drag_x, evt.button.x + camera.position.x);
                int y = so_min(drag_y, evt.button.y + camera.position.y);
                SDL_Rect rc = {x, y, w, h};
                entityManagement->boxSelect(&rc, mask);
                msg.showMessage("框选", 0);
            }
            else
            {
                entityManagement->click(evt.button.x + camera.position.x, evt.button.y + camera.position.y, mask);
                msg.showMessage("左键单击", 0);
            }
        }
    };
    auto list = entityManagement->getSelected();
    bool val = (!list->empty() && ((Ship *)list->back())->getOwnerID() == Static::playerID);
    for (auto it = components_list.begin(); it != components_list.end(); ++it)
    {
        (*it)->setVisible(val);
        (*it)->setValid(val);
    }
    return 0;
}
